using System;
using System.IO;
using Microsoft.Practices.RecipeFramework;
using PrismFactory.SoftwareFactory.Properties;

namespace PrismFactory.SoftwareFactory.Extensions.Actions.OS
{
    /// <summary>
    /// Copy the files from source dir to target dir
    /// </summary>
    public class FileCopyAction : ConfigurableAction
    {
        /// <summary>
        /// Target directory
        /// </summary>
        [Input(Required = true)]
        public string TargetDir { get; set; }

        /// <summary>
        /// Source directory
        /// </summary>
        [Input(Required = true)]
        public string SourceDir { get; set; }

        /// <summary>
        /// Filenames to copy separated by semi-colon. If this field is empty or null, all files in <see cref="SourceDir"/> are copied including the sub-folders.
        /// </summary>
        [Input]
        public string FileNames { get; set; }

        private void GuardFolderExists(string folder)
        {
            if (!Directory.Exists(folder))
            {
                throw new InvalidOperationException(String.Format(Resources.FolderDoesNotExist, folder));
            }
        }

        /// <summary>
        /// Executes the action
        /// </summary>
        public override void Execute()
        {
            GuardFolderExists(SourceDir);
            GuardFolderExists(TargetDir);

            if (string.IsNullOrEmpty(FileNames))
            {
                DirectoryCopy(SourceDir, TargetDir, true);
            }
            else
            {
                FilesCopy();                
            }
        }

        /// <summary>
        /// Undo the action
        /// </summary>
        public override void Undo()
        {
            if (string.IsNullOrEmpty(FileNames))
            {
                Directory.Delete(TargetDir, true);
            }
            else
            {
                string[] fileNames = FileNames.Split(';');
                if (Directory.Exists(TargetDir))
                {
                    foreach (string file in fileNames)
                    {
                        string targetFile = Path.Combine(TargetDir, file);
                        File.Delete(targetFile);
                    }
                }
            }
        }

        private void FilesCopy()
        {
            string[] fileNames = FileNames.Split(';');
            foreach (string file in fileNames)
            {
                string sourceFile = Path.Combine(SourceDir, file);

                if (File.Exists(sourceFile))
                {
                    string targetFile = Path.Combine(TargetDir, file);
                    File.Copy(sourceFile, targetFile, true);
                }
            }
        }

        private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);
            DirectoryInfo[] dirs = dir.GetDirectories();

            // If the source directory does not exist, throw an exception.
            if (!dir.Exists)
            {
                throw new DirectoryNotFoundException(
                    "Source directory does not exist or could not be found: "
                    + sourceDirName);
            }

            // If the destination directory does not exist, create it.
            if (!Directory.Exists(destDirName))
            {
                Directory.CreateDirectory(destDirName);
            }


            // Get the file contents of the directory to copy.
            FileInfo[] files = dir.GetFiles();

            foreach (FileInfo file in files)
            {
                // Create the path to the new copy of the file.
                string temppath = Path.Combine(destDirName, file.Name);

                // Copy the file.
                file.CopyTo(temppath, false);
            }

            // If copySubDirs is true, copy the subdirectories.
            if (copySubDirs)
            {

                foreach (DirectoryInfo subdir in dirs)
                {
                    // Create the subdirectory.
                    string temppath = Path.Combine(destDirName, subdir.Name);

                    // Copy the subdirectories.
                    DirectoryCopy(subdir.FullName, temppath, copySubDirs);
                }
            }
        }

    }
}